// Compile:
// x86-64:
// gcc -O3 -DRULES -m64 -g -Wall -ftree-parallelize-loops=4 -fomit-frame-pointer -ftree-vectorize -fno-math-errno -msse2 -march=native -mtune=native prng.c -o prng
// x86:
// gcc -m64 -O3 -g -Wall -ftree-parallelize-loops=4 range.c -o range

// Request for single Range
// Range Server:   ./range | ncat -l -p 8081
// Range Receiver: ncat -i 500 127.0.0.1 8081 > state

// Statistics //
// 16  * 2^32 takes ~1m.39sec
// 240 * 2^32 takes 

#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

#define RANGE 0x0000000F000000000ULL // 240*2^32

uint64_t lfsr      = 0x0; // 17
uint64_t mylfsr    = 0x0;
uint64_t stop_lfsr = 0x0;
uint8_t  byte;
uint64_t counter   = 0;
char 	 *p; 
int 	 Decimal_Rule = 0;
int 	 Capital_Rule = 0; 
int      Range_Rule  = 0;
int 	 i;
FILE     * pFile;

void ex_program(int sig);
void save_state();
void lfsr2string(uint64_t Lfsr, char *dst);
int  inRange(uint8_t byte);

char pass[9];

int  main()
{
  
  char    next_state [256];

  pFile = fopen ("get_state","r");
 
  if (pFile == NULL)
  { 
   printf ("Error opening file\n");
   return 1;
  }
   else
 {
     if ( fgets (next_state , 256 , pFile) != NULL )

#ifdef DEBUG
       puts (next_state);
#endif

      fclose (pFile);
   }

(void) signal(SIGINT, ex_program);

 for (i = 0; i < 8; i++)
 { 
       mylfsr += next_state[i];
       if (i<7) mylfsr <<= 8;
 }

 for (i = 8; i < 17; i++)
 { 
       stop_lfsr += next_state[i];
       if (i<16) stop_lfsr <<= 8;
 }

 lfsr = stop_lfsr;   

#ifdef DEBUG
 printf("last:\nstart at: %" PRIx64 "\n", mylfsr);
 printf("stop  at: %" PRIx64 "\n", stop_lfsr);
#endif

do {

  lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0x800000000000000Du);    

} while(counter++ != RANGE); // 240*2^32

 for(;;)
 { 
   if (inRange((lfsr & 0xFF00000000000000ULL) >> 56)) {
   if (inRange((lfsr & 0x00FF000000000000ULL) >> 48)) {
   if (inRange((lfsr & 0x0000FF0000000000ULL) >> 40)) {
   if (inRange((lfsr & 0x000000FF00000000ULL) >> 32)) {
   if (inRange((lfsr & 0x00000000FF000000ULL) >> 24)) {
   if (inRange((lfsr & 0x0000000000FF0000ULL) >> 16)) {
   if (inRange((lfsr & 0x000000000000FF00ULL) >> 8)) {
   if (inRange((lfsr & 0x00000000000000FFULL)))
    { break; }}}}}}}}
   lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0x800000000000000Du);
 }

#ifdef DEBUG
 printf("next from\nstart at: %" PRIx64 "\n", stop_lfsr);
 printf("stop  at: %" PRIx64 "\n", lfsr);
#endif

 save_state();

 sleep(5); 
 fflush(stdout);

#ifdef RECURSIVE
  lfsr      = 0x0;
  mylfsr    = 0x0;
  stop_lfsr = 0x0;
  counter   = 0;

  main ();
#endif

return 0;
}


void ex_program(int sig) {
 printf("Stoped at: %" PRIx64 "\n", lfsr);
 (void) signal(SIGINT, SIG_DFL);
 exit(0);
}

void lfsr2string(uint64_t Lfsr, char dts[9])
{
  dts[0] = (Lfsr & 0xFF00000000000000ULL) >> 56;
  dts[1] = (Lfsr & 0x00FF000000000000ULL) >> 48;
  dts[2] = (Lfsr & 0x0000FF0000000000ULL) >> 40;
  dts[3] = (Lfsr & 0x000000FF00000000ULL) >> 32;
  dts[4] = (Lfsr & 0x00000000FF000000ULL) >> 24;	
  dts[5] = (Lfsr & 0x0000000000FF0000ULL) >> 16;
  dts[6] = (Lfsr & 0x000000000000FF00ULL) >> 8;
  dts[7] = (Lfsr & 0x00000000000000FFULL);
  dts[8] = '\0';
}


void save_state() 
{
       char start_state[9];      
       char stop_state[9];      

       lfsr2string(stop_lfsr,      start_state);
       lfsr2string(lfsr,           stop_state);
       

       pFile = fopen ("get_state","w");
       fprintf (pFile, "%s %s\n", start_state, stop_state);	
       fclose (pFile);
       printf ("%s %s\n", start_state, stop_state);
}

inline int  inRange(uint8_t byte)
{
  if ((((byte >= 97) && (byte <= 122))) || (((byte >= 65) && (byte <= 90))) || (((byte >= 48) && (byte <= 57))))
	return 1;

  return 0;
}
